<?php

/**
 * View Handler
 * Display the view as HTML data
 *
 * @author Ben Rowe
 */
class ViewHTML extends ViewBase
{
	
	/**
	 * Title of the HTML document
	 *
	 * @access private
	 * @var string
	 */
	var $_title;
	
	/**
	 * data created for the template by the custom view layer.
	 * This data is converted into proper variables for use by the template
	 * 
	 * @example
	 * $_hash['foo'] = 'bar';
	 * becomes
	 * $foo = 'bar';
	 * inside the template
	 *
	 * @access private
	 * @var array
	 */
	var $_hash = array();
	
	/**
	 * Template to be loaded, as per requested by the custom view layer
	 * The template must be contained within the app/templates directory
	 * 
	 * @access private
	 * @var string
	 */
	var $_template;
	

	
	/**
	 * A list of custom js files to pull into view
	 * The initial values set below are required on every page
	 * Just before the page is actually loaded, the results of this array
	 * are compiled into one large file, which assists with file caching
	 * within the browser.
	 * The order in which the js files are set is preserved when caching
	 *
	 * @access private
	 * @var array
	 */
	var $_js = array('jquery', 'common');
	
	/**
	 * A list of custom css files to pull into view. 
	 * The initial values set below are required on every page.
	 * Just before the page is actually loaded, the result of this array
	 * is compiled into one large file, which assists with the file caching
	 * within the browser.
	 * The order in which the css files are set is preserved when caching.
	 *
	 * @access private
	 * @var array
	 */
	var $_css = array('reset', 'layout', 'common', 'print');
	
	/**
	 * execute the view object, and render it to the http
	 *
	 * @access private
	 * @return boolean
	 */
	function _exec()
	{
		global $security, $config;
		$this->_render();
		// ensure that the template exists
		if($this->_checkTemplate()) {
			extract($this->_hash);
			require_once 'app'.DS.'templates'.DS.'layout'.EXT;
			return true;
		} else {
			die('Unable to load template: '. $this->_template);	
		}
		return false;
	}
	
	/**
	 * Set the template to be loaded for this view
	 *
	 * @access protected
	 * @param string $name
	 * @param string $namespace
	 * @return boolean
	 */
	function _setTemplate($name, $namespace = false)
	{
		// if no namespace is provided, we'll provide one using the 
		// name of the inital controller
		if($namespace === false) {
			$namespace = substr($this->_name, 0, strpos($this->_name, '_')).'_';
		}
		$this->_template = strtolower($namespace.$name);
		// if the template path doesn't exist, thow an error
		if(!file_exists($this->_getTemplatePath())) {
			die('specified template ('.$this->_template.') does not exist!');
		}
		return true;	
	}
	
	/**
	 * Register a 
	 * Add a js file to be included in the stack
	 *
	 * @access protected
	 * @param string $js
	 * @return boolean
	 */
	function _setJS($js)
	{
		if(file_exists('public'.DS.'js'.DS.$js.'.js')) {
			$this->_js[] = $js;
			return true;
		}
		return false;
	}
	
	/**
	 * Build a list of <script> tags based on the called js files
	 *
	 * @access private
	 * @return html
	 */
	function _buildJS()
	{
		$js = array_unique($this->_js);
		if(!DEBUG) {
			$hash = $this->_buildMultiFileHash($js, 'js', 'public/js/');
			if($hash) {
				return '<script type="text/javascript" src="public/cache/'.$hash.'.js"></script>';
			}
		} else {
			// for debugging reasons we don't want to compile/cache the files
			$html = null;
			foreach($js as $i) {
				$html .= sprintf('<script type="text/javascript" src="public/js/%s.js"></script>'.NL, $i);
			}
			return $html;
		}
	}
	
	/**
	 * Add a css file to be included in the stack
	 *
	 * @access protected
	 * @param string $css
	 * @return boolean
	 */
	function _setCSS($css, $type = 'screen')
	{
		if(file_exists('public'.DS.'css'.DS.$css.'.css')) {
			$this->_css[] = $css;
			return true;
		}
		return false;
	}
	
	/**
	 * Generate the html required to load up the required css files
	 *
	 * @access private
	 * @return string
	 */
	function _buildCSS()
	{
		$css = array_unique($this->_css);
		if(!DEBUG) {
			// render the selected files
			$hash = $this->_buildMultiFileHash($css, 'css', 'public/css/');
			if($hash) {
				return '<link rel="stylesheet" type="text/css" href="public/cache/'.$hash.'.css" />';
			}
		} else {
			// for debugging reasons we don't want to compile/cache the files
			$html = null;
			foreach($css as $i) {
				$html .= sprintf('<link rel="stylesheet" type="text/css" href="public/css/%s.css" />'.NL, $i);
			}
			return $html;
		}
	}
	
	/**
	 * Convert an array of files into a single file, to be used for caching
	 *
	 * @param array $files the files to cache, filepaths must be relative from the application root
	 * @param string $ext the extension (lower case). This enforces only one type of file to process
	 * @param unknown_type $base
	 * @param unknown_type $cacheTo
	 * @return unknown
	 */
	function _buildMultiFileHash($files, $ext, $base, $cacheTo = 'public/cache/')
	{
		// loop through each file, if it exists add the basename + modify time to $added
		$added  = array();
		foreach($files as $f) {
			$fname = $f.'.'.$ext;
			$rel = $base.$fname;
			if(file_exists($rel)) {
				$added[] = array($fname, filemtime($rel));
			}
		}
		// check that there's at least one file existing
		if(count($added) > 0) {
			// build our hash
			$hash = md5(serialize($added));
			$href = $cacheTo.$hash.'.'.$ext;
			if(!file_exists($href)) {
				// lets make the file!
				$buffer = null;
				foreach($added as $a) {
					$content = $this->_stripComments(file_get_contents($base.$a[0]), $ext);
					$buffer .= '/* START '.$a[0].' */'.NL.$content.NL.'/* END '.$a[0].' */'.NL.NL;
				}
				$fh = fopen($href, 'w');
				if($fh) {
					fwrite($fh, $buffer, strlen($buffer));
					fclose($fh);
				}
			}
			return $hash;
		}
		return false;
	}
	
	/**
	 * Strip comments from a js/css file
	 * 
	 * @todo implement this feature
	 * @param string $content
	 * @param string $ext
	 * @returnstring
	 */
	function _stripComments($content, $ext)
	{
		return $content;
	}
	
	/**
	 * Generate the path to the template file 
	 * to be included (not included within a 
	 * function because of loss of scope) 
	 *
	 * @access private
	 * @return string
	 */
	function _getTemplatePath()
	{
		return 'app'.DS.'templates'.DS.$this->_template.EXT;
	}
	
	/**
	 * Set the page title for the HTML document
	 *
	 * @access protected
	 * @param string $title
	 * @return boolean
	 */
	function _setTitle($title)
	{
		$this->_title = $title;
		return true;
	}
	
	/**
	 * get the title set by the custom view layer
	 * used within the templates
	 *
	 * @access private
	 * @return string
	 */
	function getTitle()
	{
		return $this->_title;
	}
	
	/**
	 * Get a value from the view hash,
	 * if the key does not exist then $default is returned
	 * 
	 * @access private
	 * @param string $key
	 * @param mixed $default
	 * @return mixed
	 *
	 */
	function get($key, $default = null)
	{
		if(array_key_exists($key, $this->_hash)) {
			return $this->_hash[$key];
		}
		return $default;
	}
	
	/**
	 * set a key/value into the view has
	 *
	 * @param string $key
	 * @param mixed $value
	 * @return boolean
	 */
	function _set($key, $value)
	{
		$this->_hash[$key] = $value;
		return true;
	}
	
	/**
	 * Genereate the current base url that the application is working from
	 * The url generated always end with a closing forward slash (/)
	 *
	 * @access private
	 * @return string
	 */
	function _baseURL()
	{
		$host = $_SERVER['HTTP_HOST'];
		$script_name = pathinfo($_SERVER['SCRIPT_NAME'], PATHINFO_DIRNAME);
		if($script_name == '/') $script_name = '';
		return 'http://'.$host.$script_name.'/';
	}
	
	/**
	 * Ensure that the $_template is valid and can be called!
	 *
	 * @access private
	 * @return boolean true on valid template
	 */
	function _checkTemplate()
	{
		$path = $this->_getTemplatePath();
		if(file_exists($path)) {
			return true;
		}
		return false;
	}
	
	/**
	 * Display a list of availble variables inside of the template
	 * 
	 * @access public
	 * @return null
	 */
	function _debugShowAvailable()
	{
		var_dump($this->_hash);
	}
}

?>
